package org.budo.support.logback.configurator;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.budo.support.lang.util.SystemUtil;
import org.budo.support.logback.filter.DenyFilter;
import org.budo.support.spring.context.aware.RootApplicationContextRefreshedEventListener;
import org.slf4j.ILoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.Order;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.ConsoleAppender;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Order(Integer.MAX_VALUE) // 顺序最后
@Slf4j
public class DisableLogbackConsoleAppenderConfigurator extends RootApplicationContextRefreshedEventListener implements InitializingBean {
    private List<ConsoleAppender<?>> consoleAppenders = new ArrayList<ConsoleAppender<?>>();

    public DisableLogbackConsoleAppenderConfigurator() {
        log.info("#28 init DisableLogbackConsoleAppenderConfigurator, this=" + this);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("#34 afterPropertiesSet, this=" + this);
    }

    @Override
    protected void onRootApplicationContextRefreshedEvent(ContextRefreshedEvent contextRefreshedEvent) {
        log.info("#53 onContextRefreshedEvent, event=" + contextRefreshedEvent);

        Boolean enableConsoleAppender = this.enableConsoleAppender();
        if (enableConsoleAppender) {
            log.info("#57 enableConsoleAppender=" + enableConsoleAppender + ", this=" + this);
            return;
        }

        ILoggerFactory loggerFactory = StaticLoggerBinder.getSingleton().getLoggerFactory();
        if (null == loggerFactory || !(loggerFactory instanceof LoggerContext)) {
            log.warn("#63 StaticLoggerBinder.loggerFactory is not logback.LoggerContext");
            return;
        }

        LoggerContext loggerContext = (LoggerContext) loggerFactory;
        List<Logger> loggers = loggerContext.getLoggerList();
        for (Logger logger : loggers) {
            this.disableConsoleAppender(logger);
        }

        // 关闭应用时 将console日志启用起来
        this.addShutdownHook();
    }

    private void addShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::doEnableConsoleAppender));
    }

    private void disableConsoleAppender(Logger logger) {
        Iterator<Appender<ILoggingEvent>> appenders = logger.iteratorForAppenders();
        while (appenders.hasNext()) {
            Appender<ILoggingEvent> appender = (Appender<ILoggingEvent>) appenders.next();
            this.disableConsoleAppender_2(appender);
        }
    }

    private void disableConsoleAppender_2(Appender<ILoggingEvent> appender) {
        if (!(appender instanceof ConsoleAppender)) {
            return;
        }

        this.disableConsoleAppender_0((ConsoleAppender<?>) appender);
    }

    // 启用起来
    private void doEnableConsoleAppender() {
        for (ConsoleAppender<?> consoleAppender : this.consoleAppenders) {
            log.warn("#87 enable consoleAppender, consoleAppender=" + consoleAppender);
            System.out.println("#88 enable consoleAppender, consoleAppender=" + consoleAppender);
            System.err.println("#89 enable consoleAppender, consoleAppender=" + consoleAppender);

            consoleAppender.clearAllFilters();
        }
    }

    /**
     * @see ch.qos.logback.classic.filter.LevelFilter
     */
    private void disableConsoleAppender_0(ConsoleAppender<?> consoleAppender) {
        this.consoleAppenders.add(consoleAppender);

        // 禁用之前给出足够的提示
        log.debug("#67 before disableConsoleAppender, consoleAppender=" + consoleAppender);
        log.info("#68 before disableConsoleAppender, consoleAppender=" + consoleAppender);
        log.warn("#69 before disableConsoleAppender, consoleAppender=" + consoleAppender);
        log.error("#70 before disableConsoleAppender, consoleAppender=" + consoleAppender);

        System.out.println("#72 before disableConsoleAppender, consoleAppender=" + consoleAppender);
        System.err.println("#73 before disableConsoleAppender, consoleAppender=" + consoleAppender);

        // 禁用
        consoleAppender.clearAllFilters();
        consoleAppender.addFilter(DenyFilter.INSTANCE);

        // 禁用后试一下
        log.debug("#82 after disableConsoleAppender, consoleAppender=" + consoleAppender);
        log.info("#83 after disableConsoleAppender, consoleAppender=" + consoleAppender);
        log.warn("#84 after disableConsoleAppender, consoleAppender=" + consoleAppender);
        log.error("#85 after disableConsoleAppender, consoleAppender=" + consoleAppender);

        System.out.println("#87 after disableConsoleAppender, consoleAppender=" + consoleAppender);
        System.err.println("#88 after disableConsoleAppender, consoleAppender=" + consoleAppender);
    }

    /**
     * 允许打印console日志
     */
    protected Boolean enableConsoleAppender() {
        if (SystemUtil.isWindows()) { // windows 允许 console
            return true;
        }

        return false; // 其他的禁掉console
    }
}